#include "EditorSplitableLayoutView.h"
#include "EditorSplitableLayoutViewModel.h"

#include "Widgets/Positioners/FunctionPositionerWidget.h"
#include "Widgets/Mouse/MouseWidget.h"
#include "Widgets/RectangleWidget.h"

#include "Framework/Editor.h"
#include "Theme/EditorTheme.h"
#include "Misc/Assert.h"

void REditorSplitableLayoutView::BindViewModel(TSharedObjectPtr<REditorSplitableLayoutViewModel> InViewModel)
{
    ViewModel = InViewModel;

    //创建视图
    GASSERTEXP(OnBindItemView.IsBound());
    ItemViewModels.Resize(ViewModel->GetNodeNum());
    ItemViews.Resize(ViewModel->GetNodeNum());
    Widgets.Resize(ViewModel->GetNodeNum());
    Spliters.Resize(ViewModel->GetNodeNum());
    for (int64_t i = 0; i < ViewModel->GetNodeNum(); i++)
    {
        auto ItemViewModel = ViewModel->GetItemViewModel(i);
        if(!ItemViewModel)
        {
            continue;
        }
        ItemViewModels[i]=ItemViewModel;
        ItemViews[i] = OnBindItemView.Broadcast(ItemViewModel);
        GASSERTEXP(ItemViews[i]);
    }

    ViewModel->OnLayoutChanged.Bind(
        [this]()
        {
            auto OldItemViews = ItemViews;
            auto OldItemViewModels = ItemViewModels;

            Root->ClearSubWidgets();
            auto OldWidgets = Widgets;
            Widgets.Clear(false);
            Widgets.Resize(ViewModel->GetNodeNum());
            Spliters.Clear(false);
            Spliters.Resize(ViewModel->GetNodeNum());

            ItemViews.Resize(ViewModel->GetNodeNum());
            ItemViewModels.Resize(ViewModel->GetNodeNum());

            TVector<RWidgetPtr> NewLeafNodeWidgets;
            NewLeafNodeWidgets.Resize(ViewModel->GetNodeNum());

            for (int64_t i = 0; i < ViewModel->GetNodeNum(); i++)
            {
                NewLeafNodeWidgets[i] = nullptr;

                auto ItemViewModel = ViewModel->GetItemViewModel(i);
                if(!ItemViewModel)
                {
                    ItemViews[i]=nullptr;
                    ItemViewModels[i]=nullptr;
                    continue;
                }
                //如果之前已经有了，就不再创建
                auto FoundIndex = OldItemViewModels.Find(ItemViewModel);
                if (FoundIndex.HasValue())
                {
                    ItemViewModels[i] = ItemViewModel;
                    ItemViews[i] = OldItemViews[FoundIndex.GetValue()];

                    //重复利用控件,无需判断是否是叶子节点，因为只有叶子节点才会重复利用控件
                    NewLeafNodeWidgets[i]=OldWidgets[FoundIndex.GetValue()];
                }
                else
                {
                    ItemViewModels[i] = ItemViewModel;
                    ItemViews[i] = OnBindItemView.Broadcast(ItemViewModel);
                }

                GASSERTEXP(ItemViews[i]);
            }

            UpdateWidget(NewLeafNodeWidgets);
        }
    );

}

void REditorSplitableLayoutView::CreateWidget(RWidgetPtr InParent)
{
    Root=NewWidget<RFunctionPositionerWidget>(InParent);
    Root->Anchor.Fill(InParent);


    TWeakObjectPtr<RWidget> WeakRoot=Root;
    auto ArrangeFunction=[WeakRoot,this]()
    {
        if(Widgets.Empty())
        {
            //没有控件，不需要布局
            return;
        }

        auto Root=WeakRoot.Lock();

        auto RootSize=Root->GetPresentSize();
        auto RootPosition=Root->GetPresentAbsolutePosition();
    
        //计算每个控件的位置

        //第一个控件填满整个区域
        Widgets[0]->PresentAbsPosition=RootPosition;
        Widgets[0]->PresentSize=RootSize;

        //计算每个子控件的位置
        for(int64_t NodeIndex=0;NodeIndex<Widgets.Num();++NodeIndex)
        {
            if(!ViewModel->HasSubNode(NodeIndex))
            {
                //没有子控件，这是个叶子节点
                continue;
            }

            auto Widget=Widgets[NodeIndex];
            auto SubWidgetsIndices=ViewModel->GetSubNodeIndices(NodeIndex);
            
            //计算子控件的总体大小，确保每个子控件的大小之和等于父控件的大小
            float TotalSize=0;
            for(int64_t SubNodeIndexIndex=0;SubNodeIndexIndex<SubWidgetsIndices.Num();++SubNodeIndexIndex)
            {
                TotalSize+=ViewModel->GetSubNodeSize(NodeIndex,SubNodeIndexIndex);
            }
            TotalSize+=ViewModel->GetNodeSpliterNum(NodeIndex)*ViewModel->GetSpliterWidth();
            
            float WidgetSize=
                ViewModel->IsHorizontal(NodeIndex)
                ?Widget->GetPresentSize().X
                :Widget->GetPresentSize().Y;

            if(TotalSize!=WidgetSize)
            {
                //调整子控件的大小
                float Ratio=WidgetSize/TotalSize;
                for(int64_t SubNodeIndexIndex=0;SubNodeIndexIndex<SubWidgetsIndices.Num();++SubNodeIndexIndex)
                {
                    ViewModel->SetSubNodeSize(
                        NodeIndex
                        ,SubNodeIndexIndex
                        ,ViewModel->GetSubNodeSize(NodeIndex,SubNodeIndexIndex)*Ratio);
                }
            }
            
            //计算子控件的位置和大小
            float Offset=0;
            for(int64_t SubNodeIndexIndex=0;SubNodeIndexIndex<SubWidgetsIndices.Num();++SubNodeIndexIndex)
            {
                auto SubNodeIndex=SubWidgetsIndices[SubNodeIndexIndex];
                auto SubNodeWidget=Widgets[SubNodeIndex];

                if(ViewModel->IsHorizontal(NodeIndex))
                {
                    SubNodeWidget->PresentAbsPosition.X=Widget->PresentAbsPosition.X+Offset;
                    SubNodeWidget->PresentAbsPosition.Y=Widget->PresentAbsPosition.Y;
                    SubNodeWidget->PresentSize.X=ViewModel->GetSubNodeSize(NodeIndex,SubNodeIndexIndex);
                    SubNodeWidget->PresentSize.Y=Widget->PresentSize.Y;
                    Offset+=SubNodeWidget->PresentSize.X;

                    if(SubNodeIndexIndex<SubWidgetsIndices.Num()-1)
                    {
                        auto SpliterWidget=Spliters[NodeIndex][SubNodeIndexIndex];
                        SpliterWidget->PresentAbsPosition.X=Widget->PresentAbsPosition.X+Offset;
                        SpliterWidget->PresentAbsPosition.Y=Widget->PresentAbsPosition.Y;
                        SpliterWidget->PresentSize.X=ViewModel->GetSpliterWidth();
                        SpliterWidget->PresentSize.Y=Widget->PresentSize.Y;
                        
                        // SpliterWidget->X=Offset;
                        // SpliterWidget->Width=ViewModel->GetSpliterWidth();
                        // SpliterWidget->Anchor.VerticalFill(Widget);
                    
                        auto SpliterMouseWidget=SpliterWidget->GetSubWidget(0);
                        SpliterMouseWidget->X=
                            -(ViewModel->GetSpliterMouseWidth()-ViewModel->GetSpliterWidth())*0.5;
                        SpliterMouseWidget->Width=ViewModel->GetSpliterMouseWidth();
                        SpliterMouseWidget->Anchor.VerticalFill(Widget);
                        
                        Offset+=ViewModel->GetSpliterWidth();
                    }

                }
                else
                {
                    SubNodeWidget->PresentAbsPosition.X=Widget->PresentAbsPosition.X;
                    SubNodeWidget->PresentAbsPosition.Y=Widget->PresentAbsPosition.Y+Offset;
                    SubNodeWidget->PresentSize.X=Widget->PresentSize.X;
                    SubNodeWidget->PresentSize.Y=ViewModel->GetSubNodeSize(NodeIndex,SubNodeIndexIndex);
                    Offset+=SubNodeWidget->PresentSize.Y;

                    if(SubNodeIndexIndex<SubWidgetsIndices.Num()-1)
                    {
                        auto SpliterWidget=Spliters[NodeIndex][SubNodeIndexIndex];
                        SpliterWidget->PresentAbsPosition.X=Widget->PresentAbsPosition.X;
                        SpliterWidget->PresentAbsPosition.Y=Widget->PresentAbsPosition.Y+Offset;
                        SpliterWidget->PresentSize.X=Widget->PresentSize.X;
                        SpliterWidget->PresentSize.Y=ViewModel->GetSpliterWidth();
                    
                        auto SpliterMouseWidget=SpliterWidget->GetSubWidget(0);
                        SpliterMouseWidget->Y=
                            -(ViewModel->GetSpliterMouseWidth()-ViewModel->GetSpliterWidth())*0.5;
                        SpliterMouseWidget->Height=ViewModel->GetSpliterMouseWidth();
                        SpliterMouseWidget->Anchor.HorizontalFill(Widget);
                        
                        Offset+=ViewModel->GetSpliterWidth();
                    }


                }

                //自动隐藏大小为0的控件
                SubNodeWidget->Visible=SubNodeWidget->PresentSize.X>0 && SubNodeWidget->PresentSize.Y>0;

            }
        }

    };
    Root->ArrangeChildrenFunction.Bind(ArrangeFunction);

    TVector<RWidgetPtr> ReusedLeafWidgets;
    ReusedLeafWidgets.Resize(ViewModel->GetNodeNum());
    UpdateWidget(ReusedLeafWidgets);
}

void REditorSplitableLayoutView::UpdateWidget(const TVector<RWidgetPtr>& ReusedLeafWidgets)
{
    //创建布局树控件
    GASSERTEXP(OnFillItemWidget.IsBound());
    for(int64_t NodeIndex=0;NodeIndex<ViewModel->GetNodeNum();++NodeIndex)
    {
        if(ReusedLeafWidgets[NodeIndex])
        {
            //重复利用控件
            Root->AddSubWidget(ReusedLeafWidgets[NodeIndex]);
            Widgets[NodeIndex]=ReusedLeafWidgets[NodeIndex];
            continue;
        }

        Widgets[NodeIndex]=NewWidget<RWidget>(Root);
    }

    //填充叶子节点
    for(int64_t NodeIndex=0;NodeIndex<ViewModel->GetNodeNum();++NodeIndex)
    {
        if(ReusedLeafWidgets[NodeIndex])
        {
            //重复利用控件，不需要填充
            continue;
        }

        //为叶子节点填充控件
        if(ItemViews[NodeIndex])
        {
            OnFillItemWidget.Broadcast(ItemViews[NodeIndex],Widgets[NodeIndex]);
        }
    }

    //为非叶子结点创建Spliter控件
    //为保证spiliter控件能盖住叶子节点控件，spliter父控件为Root,且放在叶子节点控件之后创建
    for(int64_t NodeIndex=0;NodeIndex<ViewModel->GetNodeNum();++NodeIndex)
    {
        auto& Widget=Widgets[NodeIndex];
        Spliters[NodeIndex].Resize(ViewModel->GetNodeSpliterNum(NodeIndex));
        for(auto SpliterIndex=0;SpliterIndex<ViewModel->GetNodeSpliterNum(NodeIndex);++SpliterIndex)
        {
            auto& Spliter=Spliters[NodeIndex][SpliterIndex];
            auto SpliterBackground=NewWidget<RRectangleWidget>(Root);
            SpliterBackground->FillColor= REditor::Get()->CurrentTheme->SpliterColor;
            Spliter=SpliterBackground;
            
            auto SpliterMouse=NewWidget<RMouseWidget>(Spliter);
            SpliterMouse->CursorShape=[this,NodeIndex](){
                return ViewModel->IsHorizontal(NodeIndex)
                    ?EMouseCursorType::ResizeHorizontal
                    :EMouseCursorType::ResizeVertical;
            };
            SpliterMouse->Drag->bIsEnabled=true;
            SpliterMouse->Drag->OnDragStarted.Bind(
                [this,NodeIndex,SpliterIndex](){
                    ViewModel->OnSpliterDragStarted(NodeIndex,SpliterIndex);
            });
            
            SpliterMouse->Drag->OnDragMoved.Bind(
                [this,NodeIndex,SpliterIndex](const SVec2& Delta){
                    ViewModel->OnSpliterDragMoved(NodeIndex,SpliterIndex,Delta);
            });

            SpliterMouse->Drag->OnDragEnded.Bind(
                [this,NodeIndex,SpliterIndex](){
                    ViewModel->OnSpliterDragEnded(NodeIndex,SpliterIndex);
            });

            SpliterMouse->OnEntered.BindLambda(
                [this,NodeIndex,SpliterIndex](){
                    ViewModel->OnEnterSpliter(NodeIndex,SpliterIndex);
            });
            SpliterMouse->OnExited.BindLambda(
                [this,NodeIndex,SpliterIndex](){
                    ViewModel->OnExitSpliter(NodeIndex,SpliterIndex);
            });

            auto SpliterHighlight=NewWidget<RRectangleWidget>(Spliter);
            SpliterHighlight->FillColor=REditor::Get()->CurrentTheme->HighlightColor;
            SpliterHighlight->Anchor.Fill(SpliterMouse);
            SpliterHighlight->Visible=[this,NodeIndex,SpliterIndex](){
                return ViewModel->IsSpliterHighlighted(NodeIndex,SpliterIndex);
            };
        }
    }
  
}